package assignment2;
//Author Mark Mckillion, Date Completed 09/12/2011

import assignment2.Exceptions.*;//Exceptions will be used within this class.

public class CircularArrayQueue <T> implements QueueADT<T> 
{   /*This class extends all of the methods within QueueADT interface in order
     *to create a circular array style implementation of a queue.*/
    
    /*Create an integer to declare the initial size of the CircularArrayQueue if
     *the user does not specify the size*/
    private final int DEFAULT_CAPACITY = 100; 
    
    //Create integers that will record the front, rear and size of the queue.
    private int front, rear, count;
    
    //Create an array which will hold the information that the user enters.
    private T [] queue;  
  
    @SuppressWarnings("unchecked")
	public CircularArrayQueue() 
    {   //This is the default constructor, initial size: DEFAULT_CAPACITY (100).
        front = rear = count = 0;
        queue = (T[]) (new Object[DEFAULT_CAPACITY]);
    } 

    @SuppressWarnings("unchecked")
	public CircularArrayQueue (int initialCapacity) 
    {   //This contructor allows the user to define the initial size.
        front = rear = count = 0; 
        queue = ( (T[])(new Object[initialCapacity]));
    }
  
    @Override
    public void enqueue (T element) throws FullCollectionException
    {   //Exception occurs if the collection is full. (user cannot add objects)
        if (this.size() == queue.length)
            throw new FullCollectionException();
        
        //rear element of the queue is replaced with user input.
        queue[rear] = element;
        
        //use a calculation to keep the circular flow.
        rear = (rear+1) % queue.length; 
        
        //add one to count to keep a record of the size.
        count++; 
    }
  
    @Override
    public T dequeue()throws EmptyCollectionException
    {   //Exception occurs if the collection is empty. (user cannot remove objects)
        if (isEmpty())
             throw new EmptyCollectionException();
        
        //create an Object that equals the oldest item in the queue.
        T result = queue[front]; 
        
        //make that object = null.
        queue[front] = null;
        
        //use a calculation to keep the circular flow.
        front = (front+1) % queue.length; 
        
        //minus one from count to keep a record of the size.
        count--;
        
        //return the object at null to remove the item.
        return result; 
    }

    @Override
    public T first() throws EmptyCollectionException
    {   //Exception occurs if the collection is empty. (user cannot remove objects)
        if (isEmpty())
             throw new EmptyCollectionException();
        
        //return the Object at front to find the oldest item.
        return queue[front];
    }

    @Override
    public boolean isEmpty()
    {   //If statement which returns true if there is no Objects in the stack.
        if(count == 0)
        {   return true; 
        }   else
            {   return false;
            }
    }

    @Override
    public int size() 
    {   //Finds the size of the stack by returning count.
        return count;
    }
    
    @Override
    public String toString(int elem)
    {   /*Allows the program to change the object value to a string.
         *Uses an integer value to determain what Obejct to convert*/
        String str = String.valueOf(queue[elem]);
        return str;
    }
    
    public int getRear()
    {   //Returns rear value. Allows other classes can use this to access this value.
        return rear;
    }
}